/*!	 layertreestore.cpp
**	 Template File
**
**	Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
**	Copyright (c) 2008 Chris Moore
**
**	This package is free software; you can redistribute it and/or
**	modify it under the terms of the GNU General Public License as
**	published by the Free Software Foundation; either version 2 of
**	the License, or (at your option) any later version.
**
**	This package is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
**	General Public License for more details.
**
*/

#ifdef USING_PCH
#	include "pch.h"
#else
#ifdef HAVE_CONFIG_H
#	include <config.h>
#endif

#include <synfig/general.h>

#include <glibmm/main.h>

#include "layertreestore.h"
#include "iconcontroller.h"
#include <gtkmm/button.h>
#include <synfig/paramdesc.h>
#include <synfigapp/action.h>
#include <synfigapp/instance.h>
#include "app.h"
#include "instance.h"
#include <synfig/layers/layer_pastecanvas.h>
#include <synfig/layers/layer_group.h>
#include <synfig/layers/layer_switch.h>
#include <synfigapp/action_system.h>
#include <synfig/context.h>

#include <gtk/gtk.h>
#include <ETL/clock>
#include <gui/localization.h>

#endif

using namespace std;
using namespace etl;
using namespace synfig;
using namespace studio;

static LayerTreeStore::Model& ModelHack()
{
    static LayerTreeStore::Model* model(0);

    if (!model) {
        model = new LayerTreeStore::Model;
    }

    return *model;
}

LayerTreeStore::LayerTreeStore(etl::loose_handle<synfigapp::CanvasInterface> canvas_interface_):
    Gtk::TreeStore(ModelHack()),
    queued(false),
    canvas_interface_(canvas_interface_)
{
    layer_icon = Gtk::Button().render_icon_pixbuf(Gtk::StockID("synfig-layer"), Gtk::ICON_SIZE_SMALL_TOOLBAR);

    // Connect Signals to Terminals
    canvas_interface()->signal_layer_status_changed().connect(sigc::mem_fun(*this, &studio::LayerTreeStore::on_layer_status_changed));
    canvas_interface()->signal_layer_exclude_from_rendering_changed().connect(sigc::mem_fun(*this, &studio::LayerTreeStore::on_layer_exclude_from_rendering_changed));
    canvas_interface()->signal_layer_z_range_changed().connect(sigc::mem_fun(*this, &studio::LayerTreeStore::on_layer_z_range_changed));
    canvas_interface()->signal_layer_lowered().connect(sigc::mem_fun(*this, &studio::LayerTreeStore::on_layer_lowered));
    canvas_interface()->signal_layer_raised().connect(sigc::mem_fun(*this, &studio::LayerTreeStore::on_layer_raised));
    canvas_interface()->signal_layer_removed().connect(sigc::mem_fun(*this, &studio::LayerTreeStore::on_layer_removed));
    canvas_interface()->signal_layer_inserted().connect(sigc::mem_fun(*this, &studio::LayerTreeStore::on_layer_inserted));
    canvas_interface()->signal_layer_moved().connect(sigc::mem_fun(*this, &studio::LayerTreeStore::on_layer_moved));
    canvas_interface()->signal_layer_new_description().connect(sigc::mem_fun(*this, &studio::LayerTreeStore::on_layer_new_description));

    canvas_interface()->signal_time_changed().connect(sigc::mem_fun(*this, &studio::LayerTreeStore::refresh));


    set_default_sort_func(sigc::ptr_fun(index_sorter));

}

LayerTreeStore::~LayerTreeStore()
{
    if (getenv("SYNFIG_DEBUG_DESTRUCTORS")) {
        synfig::info("LayerTreeStore::~LayerTreeStore(): Deleted");
    }
}

int
LayerTreeStore::z_sorter(const Gtk::TreeModel::iterator &rhs, const Gtk::TreeModel::iterator &lhs)
{
    const Model model;

    float diff((float)(*rhs)[model.z_depth] - (float)(*lhs)[model.z_depth]);

    if (diff < 0) {
        return -1;
    }

    if (diff > 0) {
        return 1;
    }

    return 0;
}

int
LayerTreeStore::index_sorter(const Gtk::TreeModel::iterator &rhs, const Gtk::TreeModel::iterator &lhs)
{
    const Model model;

    return ((int)(*rhs)[model.index] - (int)(*lhs)[model.index]);
}

bool
LayerTreeStore::search_func(const Glib::RefPtr<TreeModel>&, int, const Glib::ustring& x, const TreeModel::iterator& iter)
{
    const Model model;

    Glib::ustring substr(x.uppercase());
    Glib::ustring label((*iter)[model.label]);
    label = label.uppercase();

    return label.find(substr) == Glib::ustring::npos;
}

Glib::RefPtr<LayerTreeStore>
LayerTreeStore::create(etl::loose_handle<synfigapp::CanvasInterface> canvas_interface_)
{
    return Glib::RefPtr<LayerTreeStore>(new LayerTreeStore(canvas_interface_));
}

template<typename T>
void LayerTreeStore::set_gvalue_tpl(Glib::ValueBase& value, const T &v, bool use_assign_operator) const
{
    Glib::Value<T> x;
    g_value_init(x.gobj(), x.value_type());

    x.set(v);

    g_value_init(value.gobj(), x.value_type());

    if (use_assign_operator) {
        value = x;
    } else {
        g_value_copy(x.gobj(), value.gobj());
    }
}

void
LayerTreeStore::get_value_vfunc(const Gtk::TreeModel::iterator& iter, int column, Glib::ValueBase& value)const
{
    if (column != model.record_type.index()
            && column != model.layer.index()
            && column != model.layer_impossible.index()
            && column != model.ghost_label.index()) {
        RecordType record_type((*iter)[model.record_type]);
        Layer::Handle layer((*iter)[model.layer]);
        bool layer_impossible((*iter)[model.layer_impossible]);
        Glib::ustring ghost_label((*iter)[model.ghost_label]);

        if (record_type == RECORD_TYPE_LAYER && layer) {
            // Real layer

            if (column == model.index.index()) {
                set_gvalue_tpl<int>(value, layer->get_depth());
            } else if (column == model.z_depth.index()) {
                set_gvalue_tpl<float>(value, layer->get_true_z_depth(canvas_interface()->get_time()));
            } else if (column == model.children_lock.index()) {
                ValueBase v(layer->get_param("children_lock"));
                set_gvalue_tpl<bool>(value, v.same_type_as(bool()) && v.get(bool()));
            } else if (column == model.label.index()) {
                set_gvalue_tpl<Glib::ustring>(value, layer->get_non_empty_description(), true);
            } else if (column == model.tooltip.index()) {
                set_gvalue_tpl<Glib::ustring>(value, layer->get_local_name(), true);
            } else if (column == model.canvas.index()) {
                set_gvalue_tpl<Canvas::Handle>(value, layer->get_canvas(), true);
            } else if (column == model.active.index()) {
                set_gvalue_tpl<bool>(value, layer->active());
            } else if (column == model.exclude_from_rendering.index()) {
                set_gvalue_tpl<bool>(value, layer->get_exclude_from_rendering());
            } else if (column == model.style.index()) {
                // Change style to italic for current layer in treeview in case of excluded from rendering
                Pango::Style style = layer->get_exclude_from_rendering()
                                     ? Pango::STYLE_ITALIC : Pango::STYLE_NORMAL;
                set_gvalue_tpl<Pango::Style>(value, style);
            } else if (column == model.weight.index()) {
                Pango::Weight weight = Pango::WEIGHT_NORMAL;

                etl::handle<Layer_PasteCanvas> paste =
                    etl::handle<Layer_PasteCanvas>::cast_dynamic(
                        layer->get_parent_paste_canvas_layer());

                if (paste) {
                    etl::handle<synfig::Canvas> sub_canvas = paste->get_param("canvas").get(sub_canvas);

                    if (sub_canvas && !sub_canvas->is_inline()) {
                        Gtk::TreeRow row = *iter;

                        if (*row.parent() && RECORD_TYPE_LAYER == (RecordType)(*row.parent())[model.record_type]) {
                            paste = etl::handle<Layer_PasteCanvas>::cast_dynamic(
                                        Layer::Handle((*row.parent())[model.layer]));
                        }
                    }
                }

                if (paste) {
                    // Change style to bold for current layer in treeview in case of visible in z_depth_visibility
                    synfig::ContextParams cp;
                    paste->apply_z_range_to_params(cp);
                    float visibility = synfig::Context::z_depth_visibility(cp, *layer);
                    weight = visibility == 1.0 && cp.z_range ? Pango::WEIGHT_BOLD : Pango::WEIGHT_NORMAL;
                }

                set_gvalue_tpl<Pango::Weight>(value, weight);
            } else if (column == model.underline.index()) {
                set_gvalue_tpl<Pango::Underline>(value, layer_impossible ? Pango::UNDERLINE_SINGLE : Pango::UNDERLINE_NONE);
            } else if (column == model.strikethrough.index()) {
                set_gvalue_tpl<bool>(value, false);
            } else if (column == model.icon.index()) {
                set_gvalue_tpl< Glib::RefPtr<Gdk::Pixbuf> >(value, get_tree_pixbuf_layer(layer->get_name()));
            } else {
                Gtk::TreeStore::get_value_vfunc(iter, column, value);
            }

            return;
        } else if (record_type == RECORD_TYPE_GHOST) {
            // Placeholder for new layer (ghost)

            if (column == model.z_depth.index()) {
                set_gvalue_tpl<float>(value, (*iter)[model.index]);
            } else if (column == model.label.index()) {
                set_gvalue_tpl<Glib::ustring>(value, ghost_label, true);
            } else if (column == model.weight.index()) {
                Pango::Weight weight = Pango::WEIGHT_NORMAL;

                if (iter->parent()) {
                    RecordType parent_record_type((*iter->parent())[model.record_type]);
                    Layer::Handle parent_layer((*iter->parent())[model.layer]);

                    etl::handle<Layer_Switch> layer_switch =
                        etl::handle<Layer_Switch>::cast_dynamic(parent_layer);

                    if (parent_record_type == RECORD_TYPE_LAYER && layer_switch)
                        if (ghost_label == layer_switch->get_param("layer_name").get(String())) {
                            weight = Pango::WEIGHT_BOLD;
                        }
                }

                set_gvalue_tpl<Pango::Weight>(value, weight);
            } else if (column == model.icon.index()) {
                set_gvalue_tpl< Glib::RefPtr<Gdk::Pixbuf> >(value, get_tree_pixbuf_layer("ghost_group"));
            } else {
                Gtk::TreeStore::get_value_vfunc(iter, column, value);
            }

            return;
        }
    }

    Gtk::TreeStore::get_value_vfunc(iter, column, value);
}

void
LayerTreeStore::set_value_impl(const Gtk::TreeModel::iterator& iter, int column, const Glib::ValueBase& value)
{

    if (column >= get_n_columns_vfunc()) {
        g_warning("LayerTreeStore::set_value_impl: Bad column (%d)", column);
        return;
    }

    if (!g_value_type_compatible(G_VALUE_TYPE(value.gobj()), get_column_type_vfunc(column))) {
        g_warning("LayerTreeStore::set_value_impl: Bad value type");
        return;
    }

    try {
        RecordType record_type((*iter)[model.record_type]);
        synfig::Layer::Handle layer((*iter)[model.layer]);
        Glib::ustring ghost_label((*iter)[model.ghost_label]);

        if (record_type == RECORD_TYPE_LAYER) {
            // Edit real layer

            if (column == model.label.index()) {
                if (!layer) {
                    return;
                }

                Glib::Value<Glib::ustring> x;
                g_value_init(x.gobj(), model.label.type());
                g_value_copy(value.gobj(), x.gobj());

                synfig::String new_desc(x.get());

                if (new_desc == layer->get_local_name()) {
                    new_desc = synfig::String();
                }

                if (new_desc == layer->get_description()) {
                    return;
                }

                synfigapp::Action::Handle action(synfigapp::Action::create("LayerSetDesc"));

                if (!action) {
                    return;
                }

                action->set_param("canvas", canvas_interface()->get_canvas());
                action->set_param("canvas_interface", canvas_interface());
                action->set_param("layer", layer);
                action->set_param("new_description", synfig::String(x.get()));

                canvas_interface()->get_instance()->perform_action(action);
                return;
            } else if (column == model.active.index()) {
                if (!layer) {
                    return;
                }

                Glib::Value<bool> x;
                g_value_init(x.gobj(), model.active.type());
                g_value_copy(value.gobj(), x.gobj());

                synfigapp::Action::Handle action(synfigapp::Action::create("LayerActivate"));

                if (!action) {
                    return;
                }

                action->set_param("canvas", canvas_interface()->get_canvas());
                action->set_param("canvas_interface", canvas_interface());
                action->set_param("layer", layer);
                action->set_param("new_status", bool(x.get()));

                canvas_interface()->get_instance()->perform_action(action);
                return;
            } else if (column == model.exclude_from_rendering.index()) {
                if (!layer) {
                    return;
                }

                Glib::Value<bool> x;
                g_value_init(x.gobj(), model.exclude_from_rendering.type());
                g_value_copy(value.gobj(), x.gobj());

                synfigapp::Action::Handle action(synfigapp::Action::create("LayerSetExcludeFromRendering"));

                if (!action) {
                    return;
                }

                action->set_param("canvas", canvas_interface()->get_canvas());
                action->set_param("canvas_interface", canvas_interface());
                action->set_param("layer", layer);
                action->set_param("new_state", bool(x.get()));

                canvas_interface()->get_instance()->perform_action(action);
                return;
            }
        } else if (record_type == RECORD_TYPE_GHOST) {
            // Edit placeholder for new layer (ghost)

            if (column == model.label.index()
                    || column == model.exclude_from_rendering.index()) {
                return;
            } else if (column == model.active.index()) {
                Glib::Value<bool> x;
                g_value_init(x.gobj(), model.active.type());
                g_value_copy(value.gobj(), x.gobj());

                if (x.get()) {
                    Canvas::Handle canvas = iter->parent()
                                            ? (*iter->parent())[model.contained_canvas]
                                            : canvas_interface()->get_canvas();

                    if (canvas) {
                        int depth = canvas->size();

                        if (Layer::Handle layer = canvas_interface()->layer_create("group", canvas)) {
                            synfigapp::Action::PassiveGrouper group(
                                canvas_interface()->get_instance().get(), _("Create Group from Ghost"));
                            canvas_interface()->layer_set_defaults(layer);
                            layer->set_description(ghost_label.c_str());
                            canvas_interface()->layer_add_action(layer);
                            canvas_interface()->layer_move_action(layer, depth);
                        }
                    }
                }

                return;
            }
        }

        Gtk::TreeStore::set_value_impl(iter, column, value);

    } catch (std::exception x) {
        g_warning("%s", x.what());
    }
}

bool
LayerTreeStore::row_draggable_vfunc(const TreeModel::Path& path)const
{
    Gtk::TreeIter iter = const_cast<LayerTreeStore*>(this)->get_iter(path);

    if (!iter) {
        return false;
    }

    RecordType record_type((*iter)[model.record_type]);
    synfig::Layer::Handle layer((*iter)[model.layer]);

    return record_type == RECORD_TYPE_LAYER && layer;
}

bool
LayerTreeStore::drag_data_get_vfunc(const TreeModel::Path& path, Gtk::SelectionData& selection_data)const
{
    if (!const_cast<LayerTreeStore*>(this)->get_iter(path)) {
        return false;
    }

    Gtk::TreeModel::Row row(*const_cast<LayerTreeStore*>(this)->get_iter(path));

    if ((bool)true) {
        Layer* layer = (RecordType)row[model.record_type] == RECORD_TYPE_LAYER
                       ? ((Layer::Handle)row[model.layer]).get()
                       : NULL;
        bool included(false);

        std::vector<Layer*> layers;
        // The following is a hack for multiple row DND
        {
            synfigapp::SelectionManager::LayerList bleh(get_canvas_interface()->get_selection_manager()->get_selected_layers());

            if (bleh.empty()) {
                selection_data.set("LAYER", 8, reinterpret_cast<const guchar*>(&layer), sizeof(layer));
                return true;
            }

            if (layer) while (!bleh.empty()) {
                    if (bleh.back().get() == layer) {
                        included = true;
                    }

                    layers.push_back(bleh.back().get());
                    bleh.pop_back();
                }
        }

        if (layer && !included) {
            layers.push_back(layer);
        }

        selection_data.set("LAYER", 8, reinterpret_cast<const guchar*>(&layers.front()), sizeof(void*)*layers.size());

        return true;
    }

    return false;
}

bool
LayerTreeStore::drag_data_delete_vfunc(const TreeModel::Path& /*path*/)
{
    return true;
}

bool
LayerTreeStore::row_drop_possible_vfunc(const TreeModel::Path& dest, const Gtk::SelectionData& selection_data)const
{

    if (synfig::String(selection_data.get_data_type()) == "LAYER") {
        TreeModel::Path dest_parent(dest);

        if (!dest_parent.up() || dest.size() == 1) {
            return true;
        } else if ((bool)const_cast<LayerTreeStore*>(this)->get_iter(dest_parent)) {
            TreeModel::Row row = *const_cast<LayerTreeStore*>(this)->get_iter(dest_parent);
            return RECORD_TYPE_LAYER == (RecordType)row[model.record_type]
                   && (bool)(Canvas::Handle)row[model.contained_canvas];
        }
    }

    return false;
}

bool
LayerTreeStore::drag_data_received_vfunc(const TreeModel::Path& dest, const Gtk::SelectionData& selection_data)
{


    bool ret = false;
    int i(0);

    synfigapp::Action::PassiveGrouper passive_grouper(canvas_interface()->get_instance().get(), _("Move Layers"));

    // Save the selection data
    synfigapp::SelectionManager::LayerList selected_layer_list = canvas_interface()->get_selection_manager()->get_selected_layers();

    if ((selection_data.get_length() >= 0) && (selection_data.get_format() == 8)) {
        synfigapp::SelectionManager::LayerList dropped_layers;

        if (synfig::String(selection_data.get_data_type()) == "LAYER")
            for (unsigned int i = 0; i < selection_data.get_length() / sizeof(void*); i++) {
                Layer::Handle l(reinterpret_cast<Layer**>(const_cast<guint8*>(selection_data.get_data()))[i]);

                if (l) {
                    dropped_layers.push_back(l);
                }
            }

        if (dropped_layers.empty()) {
            return false;
        }

        Gtk::TreeModel::Row row(*get_iter(dest));

        if (!row) {
            TreeModel::Path p(dest);
            p.up();
            row = *get_iter(p);
        }

        Canvas::Handle dest_canvas;
        Layer::Handle dest_layer;
        int dest_layer_depth = dest.back();

        if (!row) {
            dest_canvas = get_canvas_interface()->get_canvas();

            if (!dest_canvas->empty()) {
                dest_layer = dest_canvas->back();
            }

            dest_layer_depth = dest_layer ? dest_layer->get_depth() + 1 : 0;
        } else if (RECORD_TYPE_LAYER == (RecordType)row[model.record_type]) {
            // TODO: check RecordType for parent
            TreeModel::Path dest_parent(dest);

            if (!dest_parent.up() || !get_iter(dest_parent)) {
                TreeModel::Path dest_(dest);

                if (!get_iter(dest_)) {
                    dest_.prev();
                }

                if (!get_iter(dest_)) {
                    return false;
                }

                {
                    row = (*get_iter(dest_));
                    dest_canvas = (Canvas::Handle)(row[model.canvas]);
                }
            } else {
                row = (*get_iter(dest_parent));
                dest_canvas = row[model.contained_canvas];
            }

            assert(dest_canvas);
            dest_layer = row[model.layer];
        } else if (RECORD_TYPE_GHOST == (RecordType)row[model.record_type] && row.parent()) {
            // TODO: check RecordType for parent
            dest_canvas = (Canvas::Handle)(*row.parent())[model.contained_canvas];
            dest_layer_depth = dest_canvas->size();

            if (dropped_layers.size() == 1 && etl::handle<Layer_Group>::cast_dynamic(dropped_layers.front())) {
                Layer::Handle src = dropped_layers.front();
                synfigapp::Action::Handle action;

                action = synfigapp::Action::create("LayerMove");
                action->set_param("canvas", dest_canvas);
                action->set_param("canvas_interface", canvas_interface());
                action->set_param("layer", src);
                action->set_param("new_index", dest_layer_depth);
                action->set_param("dest_canvas", dest_canvas);

                if (!canvas_interface()->get_instance()->perform_action(action)) {
                    passive_grouper.cancel();
                    return false;
                }

                action = synfigapp::Action::create("LayerSetDesc");
                action->set_param("canvas", canvas_interface()->get_canvas());
                action->set_param("canvas_interface", canvas_interface());
                action->set_param("layer", dropped_layers.front());
                action->set_param("new_description", synfig::String(((Glib::ustring)row[model.ghost_label]).c_str()));

                if (!canvas_interface()->get_instance()->perform_action(action)) {
                    passive_grouper.cancel();
                    return false;
                }

                dropped_layers.clear();
                ret = true;
            } else {
                dest_layer = canvas_interface()->layer_create("group", dest_canvas);

                if (!dest_layer) {
                    return false;
                }

                canvas_interface()->layer_set_defaults(dest_layer);
                dest_layer->set_description(((Glib::ustring)row[model.ghost_label]).c_str());
                canvas_interface()->layer_add_action(dest_layer);
                canvas_interface()->layer_move_action(dest_layer, dest_layer_depth);
                dest_canvas = dest_layer->get_param("canvas").get(Canvas::Handle());
            }

            dest_layer_depth = 0;
        } else {
            return false;
        }

        for (synfigapp::SelectionManager::LayerList::const_iterator i = dropped_layers.begin(); i != dropped_layers.end(); ++i) {
            Layer::Handle src(*i);

            if (!src || dest_layer == src) {
                continue;
            }

            if (dest_canvas == src->get_canvas() && src->get_depth() < dest_layer_depth) {
                dest_layer_depth--;
            }

            if (dest_canvas == src->get_canvas() && dest_layer_depth == src->get_depth()) {
                continue;
            }

            synfigapp::Action::Handle action(synfigapp::Action::create("LayerMove"));
            action->set_param("canvas", dest_canvas);
            action->set_param("canvas_interface", canvas_interface());
            action->set_param("layer", src);
            action->set_param("new_index", dest_layer_depth);
            action->set_param("dest_canvas", dest_canvas);

            if (canvas_interface()->get_instance()->perform_action(action)) {
                ret = true;
            } else {
                passive_grouper.cancel();
                return false;
            }
        }
    }

    synfig::info("I supposedly moved %d layers", i);

    // Reselect the previously selected layers
    canvas_interface()->get_selection_manager()->clear_selected_layers();
    canvas_interface()->get_selection_manager()->set_selected_layers(selected_layer_list);

    return ret;
}

void
LayerTreeStore::queue_rebuild()
{
    if (queued) {
        return;
    }

    queued = false;
    queue_connection.disconnect();
    queue_connection = Glib::signal_timeout().connect(
                           sigc::bind_return(
                               sigc::mem_fun(*this, &LayerTreeStore::rebuild),
                               false
                           )
                           , 150);
}

void
LayerTreeStore::rebuild()
{
    if (queued) {
        queued = false;
    }

    // disconnect any subcanvas_changed connections
    std::map<synfig::Layer::Handle, sigc::connection>::iterator iter;

    for (iter = subcanvas_changed_connections.begin(); iter != subcanvas_changed_connections.end(); iter++) {
        iter->second.disconnect();
    }

    subcanvas_changed_connections.clear();

    for (iter = switch_changed_connections.begin(); iter != switch_changed_connections.end(); iter++) {
        iter->second.disconnect();
    }

    switch_changed_connections.clear();

    // etl::clock timer;timer.reset();

    // Save the selection data
    synfigapp::SelectionManager::LayerList layer_list = canvas_interface()->get_selection_manager()->get_selected_layers();
    synfigapp::SelectionManager::LayerList expanded_layer_list = canvas_interface()->get_selection_manager()->get_expanded_layers();

    // Clear out the current list
    clear();

    // Go ahead and add all the layers
    for (Canvas::reverse_iterator iter = canvas_interface()->get_canvas()->rbegin(); iter != canvas_interface()->get_canvas()->rend(); ++iter) {
        Gtk::TreeRow row_(*(prepend(children())));
        row_[model.layer_impossible] = false;
        set_row_layer(row_, *iter);
    }

    // Reselect the previously selected layers
    if (!expanded_layer_list.empty()) {
        canvas_interface()->get_selection_manager()->set_expanded_layers(expanded_layer_list);
    }

    if (!layer_list.empty()) {
        canvas_interface()->get_selection_manager()->set_selected_layers(layer_list);
    }

}

void
LayerTreeStore::refresh()
{
    etl::clock timer;
    timer.reset();

    Gtk::TreeModel::Children children_(children());
    Gtk::TreeModel::Children::iterator iter;

    if (!children_.empty())
        for (iter = children_.begin(); iter && iter != children_.end(); ++iter) {
            Gtk::TreeRow row = *iter;
            refresh_row(row);
            row_changed(get_path(iter), iter);
        }

}

void
LayerTreeStore::refresh_row(Gtk::TreeModel::Row &row)
{
    RecordType record_type = row[model.record_type];
    Layer::Handle layer = row[model.layer];

    if (record_type == RECORD_TYPE_LAYER && layer) {
        /*
        {
        	row[model.name] = layer->get_local_name();
        	if(layer->get_description().empty())
        	{
        		row[model.label] = layer->get_local_name();
        		row[model.tooltip] = Glib::ustring("Layer");
        	}
        	else
        	{
        		row[model.label] = layer->get_description();
        		row[model.tooltip] = layer->get_local_name();
        	}
        }
        */

        if (layer->dynamic_param_list().count("z_depth")) {
            row[model.z_depth] = Time::begin();
        }

        Gtk::TreeModel::Children children = row.children();
        Gtk::TreeModel::Children::iterator iter;

        if (!children.empty())
            for (iter = children.begin(); iter && iter != children.end(); ++iter) {
                Gtk::TreeRow row = *iter;
                refresh_row(row);
                row_changed(get_path(iter), iter);
            }
    }
}

void
LayerTreeStore::set_row_layer(Gtk::TreeRow &row, const synfig::Layer::Handle &handle)
{
    if (etl::handle<Layer_PasteCanvas> layer_paste = etl::handle<Layer_PasteCanvas>::cast_dynamic(handle)) {
        subcanvas_changed_connections[layer_paste].disconnect();
        subcanvas_changed_connections[layer_paste] =
            layer_paste->signal_subcanvas_changed().connect(
                sigc::mem_fun(*this, &studio::LayerTreeStore::queue_rebuild));
    }

    if (etl::handle<Layer_Switch> layer_switch = etl::handle<Layer_Switch>::cast_dynamic(handle)) {
        switch_changed_connections[layer_switch].disconnect();
        switch_changed_connections[layer_switch] =
            layer_switch->signal_possible_layers_changed().connect(
                sigc::mem_fun(*this, &studio::LayerTreeStore::queue_rebuild));
    }

    // row[model.id] = handle->get_name();
    // row[model.name] = handle->get_local_name();


    // row[model.active] = handle->active();
    row[model.record_type] = RECORD_TYPE_LAYER;
    row[model.layer] = handle;
    // row[model.canvas] = handle->get_canvas();
    // row[model.icon] = layer_icon;

    synfig::Layer::ParamList paramlist = handle->get_param_list();

    synfig::Layer::Vocab vocab = handle->get_param_vocab();
    synfig::Layer::Vocab::iterator iter;

    for (iter = vocab.begin(); iter != vocab.end(); ++iter) {
        if (iter->get_hidden()) {
            continue;
        }

        if (handle->get_param(iter->get_name()).get_type() != type_canvas) {
            continue;
        }

        {
            Canvas::Handle canvas;
            canvas = handle->get_param(iter->get_name()).get(canvas);

            if (!canvas) {
                continue;
            }

            row[model.contained_canvas] = canvas;

            std::set<String> possible_new_layers;
            std::set<String> impossible_existant_layers;

            if (etl::handle<Layer_Switch> layer_switch = etl::handle<Layer_Switch>::cast_dynamic(handle)) {
                layer_switch->get_possible_new_layers(possible_new_layers);
                layer_switch->get_impossible_existant_layers(impossible_existant_layers);
            }

            int index = canvas->size() + possible_new_layers.size();

            for (std::set<String>::const_reverse_iterator i = possible_new_layers.rbegin(); i != possible_new_layers.rend(); ++i) {
                Gtk::TreeRow row_(*(prepend(row.children())));
                set_row_ghost(row_, *i, --index);
            }

            for (Canvas::reverse_iterator iter = canvas->rbegin(); iter != canvas->rend(); ++iter) {
                Gtk::TreeRow row_(*(prepend(row.children())));
                bool xx = (bool)impossible_existant_layers.count((*iter)->get_description());
                row_[model.layer_impossible] = xx;
                set_row_layer(row_, *iter);
            }

            continue;
        }


    }
}

void
LayerTreeStore::set_row_ghost(Gtk::TreeRow &row, const synfig::String &label, int depth)
{
    row[model.index] = depth;
    row[model.record_type] = RECORD_TYPE_GHOST;
    row[model.ghost_label] = label;
}

void
LayerTreeStore::on_layer_added(synfig::Layer::Handle layer)
{
    assert(layer);
    Gtk::TreeRow row;

    if (canvas_interface()->get_canvas() == layer->get_canvas()) {
        row = *(prepend());
    } else {
        Gtk::TreeModel::Children::iterator iter;

        if (!find_canvas_row(layer->get_canvas(), iter)) {
            rebuild();
            return;
        }

        row = *(prepend(iter->children()));
    }

    set_row_layer(row, layer);
}

void
LayerTreeStore::on_layer_removed(synfig::Layer::Handle handle)
{
    if (etl::handle<Layer_PasteCanvas>::cast_dynamic(handle)) {
        subcanvas_changed_connections[handle].disconnect();
        subcanvas_changed_connections.erase(handle);
    }

    if (etl::handle<Layer_Switch>::cast_dynamic(handle)) {
        switch_changed_connections[handle].disconnect();
        switch_changed_connections.erase(handle);
    }

    Gtk::TreeModel::Children::iterator iter;

    if (find_layer_row(handle, iter)) {
        erase(iter);
    } else {
        synfig::error("LayerTreeStore::on_layer_removed():Unable to find layer to be removed, forced to rebuild...");
        rebuild();
    }
}

void
LayerTreeStore::on_layer_inserted(synfig::Layer::Handle handle, int depth)
{
    if (depth == 0) {
        on_layer_added(handle);
        return;
    }

    Gtk::TreeModel::Children children_(children());

    if (canvas_interface()->get_canvas() != handle->get_canvas()) {
        Gtk::TreeModel::Children::iterator iter;

        if (!find_canvas_row(handle->get_canvas(), iter)) {
            synfig::error("LayerTreeStore::on_layer_inserted():Unable to find canvas row, forced to rebuild...");
            rebuild();
            return;
        }

        children_ = iter->children();
    }

    Gtk::TreeModel::Children::iterator iter(children_.begin());

    while (depth-- && iter) {
        ++iter;

        if (!iter || iter == children_.end()) {
            synfig::error("LayerTreeStore::on_layer_inserted():Unable to achieve desired depth, forced to rebuild...");
            rebuild();
            return;
        }
    }

    Gtk::TreeModel::Row row(*insert(iter));
    set_row_layer(row, handle);
}

void
LayerTreeStore::on_layer_status_changed(synfig::Layer::Handle handle, bool /*x*/)
{
    Gtk::TreeModel::Children::iterator iter;

    if (find_layer_row(handle, iter)) {
        (*iter)[model.layer] = handle;
    } else {
        synfig::warning("Couldn't find layer to be activated in layer list. Rebuilding index...");
        rebuild();
    }
}

void
LayerTreeStore::on_layer_exclude_from_rendering_changed(synfig::Layer::Handle handle, bool /*x*/)
{
    Gtk::TreeModel::Children::iterator iter;

    if (find_layer_row(handle, iter)) {
        (*iter)[model.layer] = handle;
    } else {
        synfig::warning("Couldn't find layer to be excluded/included from/to rendering in layer list. Rebuilding index...");
        rebuild();
    }
}

void
LayerTreeStore::on_layer_z_range_changed(synfig::Layer::Handle handle, bool /*x*/)
{
    // Seems to not work. Need to do something different like call row_changed
    // for this layer row or all its children.
    Gtk::TreeModel::Children::iterator iter;

    if (find_layer_row(handle, iter)) {
        (*iter)[model.layer] = handle;
    } else {
        synfig::warning("Couldn't find layer to be change the z_depth range in layer list. Rebuilding index...");
        rebuild();
    }
}

void
LayerTreeStore::on_layer_lowered(synfig::Layer::Handle layer)
{
    Gtk::TreeModel::Children::iterator iter, iter2;

    if (find_layer_row(layer, iter)) {
        // Save the selection data
        iter2 = iter;
        iter2++;

        if (!iter2 || RECORD_TYPE_LAYER != (*iter2)[model.record_type]) {
            rebuild();
            return;
        }

        Gtk::TreeModel::Row row2 = *iter2;
        synfig::Layer::Handle layer2 = row2[model.layer];

        erase(iter2);
        row2 = *insert(iter);
        set_row_layer(row2, layer2);

    } else {
        rebuild();
    }
}

void
LayerTreeStore::on_layer_raised(synfig::Layer::Handle layer)
{
    Gtk::TreeModel::Children::iterator iter, iter2;

    Gtk::TreeModel::Children children_(children());

    if (find_layer_row_(layer, canvas_interface()->get_canvas(), children_, iter, iter2)) {
        if (iter != iter2 && RECORD_TYPE_LAYER == (*iter2)[model.record_type]) {
            Gtk::TreeModel::Row row2 = *iter2;
            synfig::Layer::Handle layer2 = row2[model.layer];

            erase(iter2);
            iter++;
            row2 = *insert(iter);
            set_row_layer(row2, layer2);

            return;
        }
    }

    rebuild();
}

void
LayerTreeStore::on_layer_moved(synfig::Layer::Handle layer, int depth, synfig::Canvas::Handle /*canvas*/)
{
    on_layer_removed(layer);
    on_layer_inserted(layer, depth);
}

void
LayerTreeStore::on_layer_param_changed(synfig::Layer::Handle handle, synfig::String param_name)
{
    if (param_name == "z_depth") {
        Gtk::TreeModel::Children::iterator iter;

        if (find_layer_row(handle, iter)) {
            (*iter)[model.z_depth] = Time::begin();
        }
    }


}

void
LayerTreeStore::on_layer_new_description(synfig::Layer::Handle handle, synfig::String desc)
{
    Gtk::TreeModel::Children::iterator iter;

    if (find_layer_row(handle, iter)) {
        Gtk::TreeRow row(*iter);

        Layer::Handle layer(row[model.layer]);

        if (desc.empty()) {
            // row[model.label]=layer->get_local_name();
            row[model.tooltip] = Glib::ustring(_("Layer"));
        } else
            // row[model.label]=layer->get_description();
        {
            row[model.tooltip] = layer->get_local_name();
        }
    } else {
        rebuild();
    }
}

bool
LayerTreeStore::find_canvas_row_(synfig::Canvas::Handle canvas, synfig::Canvas::Handle parent, Gtk::TreeModel::Children layers, Gtk::TreeModel::Children::iterator &iter)
{
    if (canvas == parent) {
        return false;
    }

    {
        for (iter = layers.begin(); iter && iter != layers.end(); ++iter) {
            Gtk::TreeModel::Row row = *iter;

            if (canvas == (synfig::Canvas::Handle)row[model.contained_canvas]) {
                return true;
            }
        }

        iter = children().end();
    }

    Gtk::TreeModel::Children::iterator iter2;

    for (iter2 = layers.begin(); iter2 && iter2 != layers.end(); ++iter2) {
        Gtk::TreeModel::Row row = *iter2;
        assert((bool)true);

        if (row.children().empty()) {
            continue;
        }

        Canvas::Handle sub_canvas((*row.children().begin())[model.canvas]);

        if (!sub_canvas) {
            continue;
        }

        if (find_canvas_row_(canvas, sub_canvas, iter2->children(), iter)) {
            return true;
        }
    }

    iter = children().end();
    return false;
}

bool
LayerTreeStore::find_canvas_row(synfig::Canvas::Handle canvas, Gtk::TreeModel::Children::iterator &iter)
{
    return find_canvas_row_(canvas, canvas_interface()->get_canvas(), children(), iter);
}

bool
LayerTreeStore::find_layer_row_(const synfig::Layer::Handle &layer, synfig::Canvas::Handle /*canvas*/, Gtk::TreeModel::Children layers, Gtk::TreeModel::Children::iterator &iter, Gtk::TreeModel::Children::iterator &prev)
{
    assert(layer);

    {
        for (iter = prev = layers.begin(); iter && iter != layers.end(); prev = iter++) {
            Gtk::TreeModel::Row row = *iter;

            if (RECORD_TYPE_LAYER == (RecordType)row[model.record_type]
                    && layer == (synfig::Layer::Handle)row[model.layer]) {
                return true;
            }
        }

        iter = children().end();
    }

    Gtk::TreeModel::Children::iterator iter2;

    for (iter2 = layers.begin(); iter2 && iter2 != layers.end(); ++iter2) {
        Gtk::TreeModel::Row row = *iter2;
        assert((bool)true);

        if (row.children().empty()) {
            continue;
        }

        if (RECORD_TYPE_LAYER != (RecordType)row[model.record_type]) {
            continue;
        }

        Canvas::Handle canvas((*row.children().begin())[model.canvas]);

        if (!canvas) {
            continue;
        }

        if (find_layer_row_(layer, canvas, iter2->children(), iter, prev)) {
            return true;
        }
    }

    iter = children().end();
    return false;
}

bool
LayerTreeStore::find_layer_row(const synfig::Layer::Handle &layer, Gtk::TreeModel::Children::iterator &iter)
{
    Gtk::TreeModel::Children::iterator prev;
    return find_layer_row_(layer, canvas_interface()->get_canvas(), children(), iter, prev);
}

bool
LayerTreeStore::find_prev_layer_row(const synfig::Layer::Handle &layer, Gtk::TreeModel::Children::iterator &prev)
{
    Gtk::TreeModel::Children::iterator iter;

    if (!find_layer_row_(layer, canvas_interface()->get_canvas(), children(), iter, prev)) {
        return false;
    }

    if (iter == children().begin()) {
        return false;
    }

    return true;
}